use crate::glutils::ShaderProgram;
use crate::glutils::{VertexArray, VertexLayout};
use crate::shaders;
use crate::camera::{Camera, Camera2D};

use zmath::{Vec4, Mat4};

pub struct RectBatcher {
    vertices: Vec<f32>,
    indices: Vec<u32>,
    vao: VertexArray,
    shader: ShaderProgram,
    num_vertices: i32,
}

impl RectBatcher {
    pub fn new(extent: (f32, f32)) -> Self {
        let shader = ShaderProgram::from_source(shaders::GEO_VERTEX_SHADER_SRC, shaders::GEO_FRAGMENT_SHADER_SRC);
        shader.set_uniform("proj", Mat4::ortho(extent.0, extent.1, 1.0, -1.0));
        Self {
            vertices: Vec::new(),
            indices: Vec::new(),
            vao: VertexArray::new(VertexLayout::P1C),
            shader,
            num_vertices: 0
        }
    }

    pub fn begin(&mut self) {
        self.vertices.clear();
        self.indices.clear();
        self.num_vertices = 0;
    }

    pub fn draw_rect(&mut self, x: f32, y: f32, width: f32, height: f32, colors: &[Vec4]) {
        let hw = width / 2.0;
        let hh = height / 2.0;
        let x1 = x - hw;
        let y1 = y - hh;
        let x2 = x + hw;
        let y2 = y + hh;

        self.vertices.push(x1);
        self.vertices.push(y1);

        if colors.len() >= 1 {
            self.vertices.push(colors[0].0);
            self.vertices.push(colors[0].1);
            self.vertices.push(colors[0].2);
            self.vertices.push(colors[0].3);
        } else {
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
        }
        
        
        self.vertices.push(x2);
        self.vertices.push(y1);

        if colors.len() >= 4 {
            self.vertices.push(colors[1].0);
            self.vertices.push(colors[1].1);
            self.vertices.push(colors[1].2);
            self.vertices.push(colors[1].3);
        } else if colors.len() == 1 {
            self.vertices.push(colors[0].0);
            self.vertices.push(colors[0].1);
            self.vertices.push(colors[0].2);
            self.vertices.push(colors[0].3);
        } else {
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
        }
        
        self.vertices.push(x2);
        self.vertices.push(y2);

        if colors.len() >= 4 {
            self.vertices.push(colors[2].0);
            self.vertices.push(colors[2].1);
            self.vertices.push(colors[2].2);
            self.vertices.push(colors[2].3);
        } else if colors.len() == 1 {
            self.vertices.push(colors[0].0);
            self.vertices.push(colors[0].1);
            self.vertices.push(colors[0].2);
            self.vertices.push(colors[0].3);
        } else {
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
        }

        self.vertices.push(x1);
        self.vertices.push(y2);

        if colors.len() >= 4 {
            self.vertices.push(colors[3].0);
            self.vertices.push(colors[3].1);
            self.vertices.push(colors[3].2);
            self.vertices.push(colors[3].3);
        } else if colors.len() == 1 {
            self.vertices.push(colors[0].0);
            self.vertices.push(colors[0].1);
            self.vertices.push(colors[0].2);
            self.vertices.push(colors[0].3);
        } else {
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
            self.vertices.push(0.0);
        }

        let start = self.num_vertices as u32;

        self.indices.push(start + 0);
        self.indices.push(start + 1);
        self.indices.push(start + 2);

        self.indices.push(start + 2);
        self.indices.push(start + 3);
        self.indices.push(start + 0);

        self.num_vertices += 4;
    }

    pub fn present(&mut self, camera: Option<&Camera2D>) {
        self.vao.set_triangles(&self.vertices, &self.indices);
        self.shader.use_program();
        if let Some(camera) = camera {
            self.shader.set_uniform("trans", camera.mat());
        } else {
            self.shader.set_uniform("trans", Mat4::identity());
        }

        self.vao.bind();
        self.vao.draw(gl::TRIANGLES, self.num_vertices * 6 / 4);
        self.vao.unbind();
    }
}